/*
* $Id: InspectManager.cpp 302 2011-04-08 15:18:13Z volok-aleksej@yandex.ru $
*
* Copyright 2010-2011 by Volokitin Alexey
* All rights reserved
*
*/
#include "Common/include.h"
#include "JournalInterface.h"
#include "InspectManager.h"
#include "Database/Tables/JournalTable.h"
#include "Database/Operation/GetInspectOperation.h"
#include "Database/Operation/AddInspectOperation.h"
#include "Database/Operation/ChangeInspectOperation.h"
#include "Database/Operation/DeleteOperation.h"
#include "Database/DatabaseNames.h"
#include "Event/EventId.h"

#include "RefObject.h"
CRefObject<CInspectManager> g_InspectManager;
CInspectManager* IJournalComponent::GetInspectManager(){
	return g_InspectManager.GetObject();
}

/************************************************************************/
/*                CInspectManager::journal                              */
/************************************************************************/
CInspectManager::journal::journal()
: m_nIdFamily(0), m_date(0), m_nFrame(0), m_nStrength(0),
m_nQBState(Journal::DEFAULT), m_nWax(0), m_nAmbrosia(0), m_nEvacuation(0),
m_nDieting(0), m_nDisease(Journal::HEALTHY), m_nIdRecord(0){}
CInspectManager::journal::journal(const journal& jrn){
	operator = (jrn);
}
void CInspectManager::journal::operator=(const journal& jrn){
	m_nIdFamily = jrn.m_nIdFamily;
	m_date = jrn.m_date;
	m_nFrame = jrn.m_nFrame;
	m_nStrength = jrn.m_nStrength;
	m_nQBState = jrn.m_nQBState;
	m_nWax = jrn.m_nWax;
	m_nAmbrosia = jrn.m_nAmbrosia;
	m_nEvacuation = jrn.m_nEvacuation;
	m_nDieting = jrn.m_nDieting;
	m_nDisease = jrn.m_nDisease;
	m_strNote = jrn.m_strNote;
	m_nIdRecord = jrn.m_nIdRecord;
}
/************************************************************************/
/*                 CInspectManager::inspect                             */
/************************************************************************/
CInspectManager::inspect::inspect()
: m_nHoney(0), m_nBrood(0), m_nGoodHoney(0),
m_nOpenBrood(0), m_nCloseBrood(0), m_nIdHousing(0){}
CInspectManager::inspect::inspect(const inspect& ins){
	operator = (ins);
}
void CInspectManager::inspect::operator=(const inspect& ins){
	m_strNameHousing = ins.m_strNameHousing;
	m_nIdHousing = ins.m_nIdHousing;
	m_nHoney = ins.m_nHoney;
	m_nBrood = ins.m_nBrood;
	m_nGoodHoney = ins.m_nGoodHoney;
	m_nOpenBrood = ins.m_nOpenBrood;
	m_nCloseBrood = ins.m_nCloseBrood;
}

/************************************************************************/
/*                     CInspectManager::lastInspect                     */
/************************************************************************/
CInspectManager::lastInspect::lastInspect()
: m_nIdJournal(0), m_nFrame(0), m_nStrength(0), m_nHousing(0),
m_nHoney(0), m_nBrood(0), m_nWax(0), m_nQBState(0){}
CInspectManager::lastInspect::lastInspect(const lastInspect& ins){
	operator = (ins);
}
void CInspectManager::lastInspect::operator=(const lastInspect& ins){
	m_nIdJournal = ins.m_nIdJournal;
	m_nFrame = ins.m_nFrame;
	m_nStrength = ins.m_nStrength;
	m_nHoney = ins.m_nHoney;
	m_nBrood = ins.m_nBrood;
	m_nWax = ins.m_nWax;
	m_nQBState = ins.m_nQBState;
	m_nHousing = ins.m_nHousing;
}

/************************************************************************/
/*                       CInspectManager                                */
/************************************************************************/
CInspectManager::CInspectManager(){}
CInspectManager::~CInspectManager(){}

void CInspectManager::Init(){
	IDatabase* pDb = IDatabaseManager::GetDatabaseManager()->OpenDatabase(JOURNAL_DATABASE_NAME);
	CJournalTable journalTable;
	IResult* pResult = journalTable.GetValue(pDb);
	for(int i = 0; i < (int)pResult->GetSizeResult(); i++){
		CJournalTable::content* pContent = (CJournalTable::content*)(*pResult)[i];
		journal &jrn = m_aJournal[pContent->s_nId];
		jrn.m_date = pContent->s_date;
		jrn.m_nFrame = pContent->s_nFrame;
		jrn.m_nStrength = pContent->s_nStrength;
		jrn.m_nQBState = pContent->s_QueenBee;
		jrn.m_nWax = pContent->s_nWax;
		jrn.m_nAmbrosia = pContent->s_nAmbrosia;
		jrn.m_nEvacuation = pContent->s_nEvacuation;
		jrn.m_nDieting = pContent->s_nFeeding;
		jrn.m_nDisease = pContent->s_disease;
		jrn.m_strNote = pContent->s_strNote;
		jrn.m_nIdRecord = pContent->s_nIdRecord;
		jrn.m_nIdFamily = pContent->s_nIdFamily;
		m_aFmlJrnl[jrn.m_nIdFamily].push_back(pContent->s_nId);
		std::map<int, int>::iterator it = m_aFmlLastJrnl.find(jrn.m_nIdFamily);
		if(jrn.m_nIdFamily && it == m_aFmlLastJrnl.end() || m_aJournal[it->second].m_date < pContent->s_date)
			m_aFmlLastJrnl[jrn.m_nIdFamily] = pContent->s_nId;
	}
	pResult->Free();
	CGetInspectOperation insOperation;
	pResult = insOperation.GetValue(pDb);
	for(int i = 0; i < (int)pResult->GetSizeResult(); i++){
		CGetInspectOperation::content* pContent = (CGetInspectOperation::content*)(*pResult)[i];
		std::vector<inspect> &aInspects = m_aInspects[pContent->s_nIdJournal];
		inspect ins;
		ins.m_strNameHousing = pContent->s_strNameHousing;
		ins.m_nIdHousing = pContent->s_nIdHousing;
		ins.m_nHoney = pContent->s_nHoney;
		ins.m_nBrood = pContent->s_nBrood;
		ins.m_nGoodHoney = pContent->s_nGoodsHoney;
		ins.m_nOpenBrood = pContent->s_nOpenBrood;
		ins.m_nCloseBrood = pContent->s_nCloseBrood;
		aInspects.push_back(ins);
	}
	pResult->Free();
	IDatabaseManager::GetDatabaseManager()->CloseDatabase(pDb);
}

std::map<int, CInspectManager::journal> CInspectManager::GetFamilyJournal(int nIdFamily){
	std::map<int, journal> aJournals;
	for(std::vector<int>::iterator it = m_aFmlJrnl[nIdFamily].begin(); it != m_aFmlJrnl[nIdFamily].end(); it++){
		aJournals.insert(std::make_pair(*it, m_aJournal[*it]));
	}
	return aJournals;
}

CInspectManager::lastInspect CInspectManager::GetFamilyLastJournal(int nIdFamily){
	lastInspect ins;
	std::map<int, int>::iterator it = m_aFmlLastJrnl.find(nIdFamily);
	if(it == m_aFmlLastJrnl.end())
		return ins;
	journal& jrn = m_aJournal[it->second];
	ins.m_nIdJournal = it->second;
	ins.m_nStrength = jrn.m_nStrength;
	ins.m_nFrame = jrn.m_nFrame;
	ins.m_nWax = jrn.m_nWax;
	ins.m_nQBState = jrn.m_nQBState;
	std::vector<inspect>& aInspects = m_aInspects[it->second];
	ins.m_nHousing = (int)aInspects.size();
	for(std::vector<inspect>::iterator it1 = aInspects.begin(); it1 != aInspects.end(); it1++){
		ins.m_nHoney += it1->m_nHoney;
		ins.m_nBrood += it1->m_nBrood;
	}
	return ins;
}

std::vector<CInspectManager::inspect> CInspectManager::GetInspects(int nIdJournal){
	return m_aInspects[nIdJournal];
}

CInspectManager::journal CInspectManager::GetJournal(int nIdJournal){
	return m_aJournal[nIdJournal];
}

void CInspectManager::AddInspect(journal jrn, const std::vector<inspect>& aInspects,
								 const std::map<std::tstring, std::tstring>& aUserFields){
	IDatabase* pDb = IDatabaseManager::GetDatabaseManager()->OpenDatabase(JOURNAL_DATABASE_NAME);
	pDb->BeginTransaction(_T("Add Inspect"));
	CAddInspectOperation addOperation;
	addOperation.m_content.s_nIdFamily = jrn.m_nIdFamily;
	addOperation.m_content.s_date = jrn.m_date;
	addOperation.m_content.s_nFrame = jrn.m_nFrame;
	addOperation.m_content.s_nStrength = jrn.m_nStrength;
	addOperation.m_content.s_nWax = jrn.m_nWax;
	addOperation.m_content.s_beeQueenStatus = jrn.m_nQBState;
	addOperation.m_content.s_nAmbrosia = jrn.m_nAmbrosia;
	addOperation.m_content.s_nPumpHoney = jrn.m_nEvacuation;
	addOperation.m_content.s_nFeeding = jrn.m_nDieting;
	addOperation.m_content.s_disease = jrn.m_nDisease;
	addOperation.m_content.s_strNote = jrn.m_strNote;
	addOperation.m_content.s_aUserFields = aUserFields;
	for(std::vector<inspect>::const_iterator it = aInspects.begin(); it != aInspects.end(); it++){
		addOperation.m_content.s_aInspects.push_back(CAddInspectOperation::inspect(it->m_nIdHousing,
			it->m_nIdHousing ? _T("") : it->m_strNameHousing, it->m_nBrood, it->m_nHoney, it->m_nOpenBrood,
			it->m_nCloseBrood, it->m_nGoodHoney));
	}
	addOperation.AddValue(pDb);
	pDb->EndTransaction(_T("Add Inspect"));
	IDatabaseManager::GetDatabaseManager()->CloseDatabase(pDb);

	jrn.m_nIdRecord = addOperation.m_content.s_nIdRecord;
	m_aJournal.insert(std::make_pair(addOperation.m_content.s_nId, jrn));
	m_aFmlJrnl[jrn.m_nIdFamily].push_back(addOperation.m_content.s_nId);
	int& lastIns = m_aFmlLastJrnl[jrn.m_nIdFamily];
	if(m_aJournal[lastIns].m_date < jrn.m_date)
		lastIns = addOperation.m_content.s_nId;
	m_aInspects[addOperation.m_content.s_nId] = aInspects;
	IEventManager::GetEventManager()->SendEvent(JOURNAL_DB_CHANGE_EVENT);
}

void CInspectManager::ChangeInspect(int nId, journal jrn, const std::vector<inspect>& aInspects,
									const std::map<std::tstring, std::tstring>& aUserFields){
	IDatabase* pDb = IDatabaseManager::GetDatabaseManager()->OpenDatabase(JOURNAL_DATABASE_NAME);
	pDb->BeginTransaction(_T("Update Inspect"));
	CChangeInspectOperation changeOperation;
	changeOperation.m_content.s_nId = nId;
	changeOperation.m_content.s_date = jrn.m_date;
	changeOperation.m_content.s_nFrame = jrn.m_nFrame;
	changeOperation.m_content.s_nStrength = jrn.m_nStrength;
	changeOperation.m_content.s_nWax = jrn.m_nWax;
	changeOperation.m_content.s_beeQueenStatus = jrn.m_nQBState;
	changeOperation.m_content.s_nAmbrosia = jrn.m_nAmbrosia;
	changeOperation.m_content.s_nPumpHoney = jrn.m_nEvacuation;
	changeOperation.m_content.s_nFeeding = jrn.m_nDieting;
	changeOperation.m_content.s_disease = jrn.m_nDisease;
	changeOperation.m_content.s_strNote = jrn.m_strNote;
	changeOperation.m_content.s_aUserFields = aUserFields;
	for(std::vector<inspect>::const_iterator it = aInspects.begin(); it != aInspects.end(); it++){
		changeOperation.m_content.s_aInspects.push_back(CChangeInspectOperation::inspect(it->m_nIdHousing,
			it->m_nIdHousing ? _T("") : it->m_strNameHousing, it->m_nBrood, it->m_nHoney, it->m_nOpenBrood,
			it->m_nCloseBrood, it->m_nGoodHoney));
	}
	changeOperation.UpdateValue(pDb);
	jrn.m_nIdRecord = changeOperation.m_content.s_nIdRecord;
	pDb->EndTransaction(_T("Update Inspect"));
	IDatabaseManager::GetDatabaseManager()->CloseDatabase(pDb);
	m_aJournal[nId] = jrn;
	int& lastIns = m_aFmlLastJrnl[jrn.m_nIdFamily];
	if(m_aJournal[lastIns].m_date <= jrn.m_date)
		lastIns = nId;
	m_aInspects[nId] = aInspects;
	IEventManager::GetEventManager()->SendEvent(JOURNAL_DB_CHANGE_EVENT);
}

void CInspectManager::DeleteInspect(int nId){
	IDatabase* pDb = IDatabaseManager::GetDatabaseManager()->OpenDatabase(JOURNAL_DATABASE_NAME);
	pDb->BeginTransaction(_T("Delete Inspect"));
	DelInspect(nId, pDb);
	pDb->EndTransaction(_T("Delete Inspect"));
	IDatabaseManager::GetDatabaseManager()->CloseDatabase(pDb);
	std::map<int, journal>::iterator it = m_aJournal.find(nId);
	if(it != m_aJournal.end()){
		int nIdFamily = it->second.m_nIdFamily;
		m_aJournal.erase(it);
		std::map<int, std::vector<inspect> >::iterator it1 = m_aInspects.find(nId);
		if(it1 != m_aInspects.end())
			m_aInspects.erase(it1);
		std::vector<int>& aFJ = m_aFmlJrnl[nIdFamily];
		std::vector<int>::iterator it2 = std::find(aFJ.begin(), aFJ.end(), nId);
		if(it2 != aFJ.end())
			aFJ.erase(it2);
		std::map<int, int>::iterator it3 = m_aFmlLastJrnl.find(nIdFamily);
		if(it3->second == nId){
			int& ln = m_aFmlLastJrnl[nIdFamily] = 0;
			for(std::vector<int>::iterator it4 = m_aFmlJrnl[nIdFamily].begin(); it4 != m_aFmlJrnl[nIdFamily].end(); it4++){
				if(ln == 0 || m_aJournal[ln].m_date <= m_aJournal[*it4].m_date)
					ln = *it4;
			}
		}
	}
	IEventManager::GetEventManager()->SendEvent(JOURNAL_DB_CHANGE_EVENT);
}

void CInspectManager::DeleteInspects(int nIdFamily){
	IDatabase* pDb = IDatabaseManager::GetDatabaseManager()->OpenDatabase(JOURNAL_DATABASE_NAME);
	std::vector<int>& aIds = m_aFmlJrnl[nIdFamily];
	for(std::vector<int>::iterator it = aIds.begin(); it != aIds.end(); it++){
		DelInspect(*it, pDb);
		m_aJournal.erase(*it);
		m_aInspects.erase(*it);
	}
	IDatabaseManager::GetDatabaseManager()->CloseDatabase(pDb);
	m_aFmlLastJrnl.erase(nIdFamily);
	m_aFmlJrnl.erase(nIdFamily);
	IEventManager::GetEventManager()->SendEvent(JOURNAL_DB_CHANGE_EVENT);
}

void CInspectManager::DelInspect(int nId, IDatabase* pDb){
	CDeleteOperation operation;
	operation.m_content.s_nId = nId;
	operation.m_content.s_type = CDeleteOperation::content::JOURNAL;
	operation.DeleteValue(pDb);
}
